package com.bitcointoolkit.dao.config;

import java.sql.SQLException;

import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;

/**
 * @author caisirius
 * @date 2017年12月18日
 */
@Configuration
@EnableTransactionManagement
@MapperScan({"com.bitcointoolkit.dao.mapper"})
public class MyBatisConfig{

    @Autowired
    private Environment env;
    
    private static final String DB_URL = "db.url";
    private static final String DB_USERNAME = "db.username";
    private static final String DB_PASSWORD = "db.password";
    private static final String DB_MAX_ACTIVE = "db.maxActive";

    @Bean
    public DruidDataSource dataSource() throws SQLException {
        final String url = Preconditions.checkNotNull(env.getProperty(DB_URL));
        final String username = Preconditions.checkNotNull(env.getProperty(DB_USERNAME));
        final String password = env.getProperty(DB_PASSWORD);
        final int maxActive = Integer.parseInt(env.getProperty(DB_MAX_ACTIVE, "200"));
        
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(maxActive);
        dataSource.setInitialSize(2);
        dataSource.setMinIdle(2);
        dataSource.setTimeBetweenEvictionRunsMillis(10000);
        dataSource.setMinEvictableIdleTimeMillis(60000);
        dataSource.setValidationQuery("SELECT 'x'");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
        dataSource.setRemoveAbandoned(true);
        dataSource.setRemoveAbandonedTimeout(1800);
        dataSource.setLogAbandoned(true);
        dataSource.setFilters("stat");
        dataSource.setConnectionProperties("druid.stat.slowSqlMillis=100");
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        //数据源
        factoryBean.setDataSource(dataSource());
        /** 
        | Mybatis全局配置设置
        |
        | 可配置选项                                        默认值, 描述
        |
        | aggressiveLazyLoading     true, 当设置为‘true’的时候，懒加载的对象可能被任何懒属性全部加载。否则，每个属性都按需加载。
        | multipleResultSetsEnabled true, 允许和不允许单条语句返回多个数据集（取决于驱动需求）
        | useColumnLabel            true, 使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档，或者用这两个不同的选项进行测试一下。
        | useGeneratedKeys          false, 允许JDBC 生成主键。需要驱动器支持。如果设为了true，这个设置将强制使用被生成的主键，有一些驱动器不兼容不过仍然可以执行。
        | autoMappingBehavior       PARTIAL, 指定MyBatis 是否并且如何来自动映射数据表字段与对象的属性。PARTIAL将只自动映射简单的，没有嵌套的结果。FULL 将自动映射所有复杂的结果。
        | defaultExecutorType       SIMPLE, 配置和设定执行器，SIMPLE 执行器执行其它语句。REUSE 执行器可能重复使用prepared statements 语句，BATCH执行器可以重复执行语句和批量更新。
        | defaultStatementTimeout   null, 设置一个时限，以决定让驱动器等待数据库回应的多长时间为超时
        | **/
        org.apache.ibatis.session.Configuration conf = new org.apache.ibatis.session.Configuration();
        conf.setCacheEnabled(true);
        conf.setLazyLoadingEnabled(true);
        conf.setMultipleResultSetsEnabled(true);
        conf.setUseColumnLabel(true);
        conf.setDefaultExecutorType(ExecutorType.REUSE);
        conf.setDefaultStatementTimeout(30000);
        factoryBean.setConfiguration(conf);
        //插件
        factoryBean.setPlugins(new Interceptor[]{paginationInterceptor()});
        return factoryBean.getObject();
    }
    
    @Bean
    public Interceptor paginationInterceptor(){
    	PageHelper pi = new PageHelper();
    	return pi;
    }

    @Bean
    public DataSourceTransactionManager transactionManager() throws SQLException {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }
    
}
